package com.oocl.scan.handler;

import static com.oocl.scan.utils.ScanConstants.DB_DAO_TYPE;
import static com.oocl.scan.utils.ScanConstants.EMS_BROKER_TYPE;
import static com.oocl.scan.utils.ScanConstants.JAVA_TYPE;
import static com.oocl.scan.utils.ScanConstants.WS_CONTROLLER_TYPE;
import static com.oocl.scan.utils.ScanConstants.WS_REST_TYPE;
import static com.oocl.scan.utils.ScanConstants.WS_SOAP_TYPE;
import com.oocl.scan.jdt.parser.ModifierParser;
import com.oocl.scan.model.Component;
import com.oocl.scan.model.JavaClassElement;
import com.oocl.scan.model.ModelResult;
import com.oocl.scan.model.Relationship;
import com.oocl.scan.utils.ScanConstants;
import java.util.List;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.TypeDeclaration;

public class JavaClassHandler extends BaseHandler{

  @Override
  public void handle(JavaClassElement element) {
    if (!isModelClass(element)) {
      Component component = getJavaLevelComponent(element);
      addToComponentStore(component);
      buildMethodLevelComponent(component.getName(), component.getDomain(), component.getModule(), component.getType(), element);
    } else if (isModelClass(element)) {
//      String fullClassName = element.getPackageDeclaration().getName().toString() + "." + element.getClassName();
//      buildMethodLevelComponent(fullClassName,element.getDomainName(),element.getModuleName(),ScanConstants.MODEL_METHOD_TYPE, element);
    }
  }

  private Component getJavaLevelComponent(JavaClassElement element) {
    String type = getClassType(element);
    String className = element.getClassName();
    String packageName = element.getPackageDeclaration().getName().toString() + ".";
    Component component = new Component(packageName + className, type, element.getModuleName(), element.getDomainName().toUpperCase());
    return component;
  }

  private String getClassType(JavaClassElement element) {
    String className = element.getClassName();
    String parent = element.getParent() != null ? element.getParent().toString() : null;
    if (isDao(className, element.getJavaClassFullName())) {
      return DB_DAO_TYPE;
    }
    if (isBroker(parent, element.getImplementList())) {
      return EMS_BROKER_TYPE;
    }
    if (ModifierParser.isRestfulClass(element.getTypeDeclaration())) {
      return WS_REST_TYPE;
    }
    if (isController(element)) {
      return WS_CONTROLLER_TYPE;
    }
    if (isSoap((className))) {
      return WS_SOAP_TYPE;
    }
    return JAVA_TYPE;
  }

  private void buildMethodLevelComponent(String fullClassName, String domain, String module, String type, JavaClassElement element) {
    List<MethodDeclaration> methodDeclarationList = element.getMethodDeclarationList();
    for (MethodDeclaration methodDeclaration : methodDeclarationList) {
      Component componentWithMethod = new Component();
      if (!element.getClassName().equals(methodDeclaration.getName())) {
        String name = fullClassName + "-" + methodDeclaration.getName();
        componentWithMethod.setDomain(domain);
        componentWithMethod.setModule(module);
        componentWithMethod.setType(type);
        componentWithMethod.setName(name);
        addToComponentStore(componentWithMethod);
        if(needToBuildMethodAndClassRelationship(type)){
          buildMethodAndClassRelationship(element,componentWithMethod);
        }
      }
    }
  }

  private boolean needToBuildMethodAndClassRelationship(String type) {
    return type.equals(DB_DAO_TYPE) || type.equals(WS_CONTROLLER_TYPE) || type.equals(WS_CONTROLLER_TYPE) || type.equals(WS_SOAP_TYPE);
  }

  private void buildMethodAndClassRelationship(JavaClassElement element, Component methodLevelComponent){
    Relationship relationship = new Relationship();
    relationship.setFrom(methodLevelComponent.getName());
    relationship.setFromModule(methodLevelComponent.getModule());
    relationship.setTo(element.getJavaClassFullName());
    relationship.setToModule(element.getModuleName());
    relationship.setType(ScanConstants.RELATION_TYPE_IN);
    addToRelationshipStore(relationship);
  }

  private boolean isSoap(String name) {
    return name.contains(ScanConstants.SOAP_CLASS);
  }

  private boolean isBroker(String parent, List implementList) {
    if (ScanConstants.FRM_BASE_MESSAGE_BROKER.equals(parent)) {
      return true;
    }
    if (implementList.size() != 0) {
      for (Object impl : implementList) {
        if (ScanConstants.FRM_APPLICATION_MESSAGE_BROKER.equals(impl.toString())) {
          return true;
        }
      }
    }
    return false;
  }

  boolean isModelClass(JavaClassElement element) {
    TypeDeclaration typeDeclaration = element.getTypeDeclaration();
    NormalAnnotation tableAnnotation = ModifierParser.getAnnotation(typeDeclaration, ModelResult.TABLE);
    NormalAnnotation entityAnnotation = ModifierParser.getAnnotation(typeDeclaration, ModelResult.ENTITY);
    if (tableAnnotation != null && entityAnnotation != null) {
      return true;
    }
    return false;
  }
}
